package com.htfyun.factorytest.myrecorder;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.text.TextUtils;

import com.htfyun.factorytest.utils.DebugLog;
import com.htfyun.factorytest.utils.PcmToWav;
import com.htfyun.factorytest.utils.executor.AppExecutors;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class RecorderOperator {
    private AudioRecord mRecord;
    // 音频获取源
    private int audioSource = MediaRecorder.AudioSource.MIC;

    // 设置音频采样率，44100是目前的标准，但是某些设备仍然支持22050，16000，11025
    private int sampleRateInHz = 16000;// 44100;
    // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道，CHANNEL_CONFIGURATION_MONO为单声道
    private int channelConfig = AudioFormat.CHANNEL_IN_MONO;//AudioFormat.CHANNEL_CONFIGURATION_MONO;// AudioFormat.CHANNEL_IN_STEREO;
    // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
    private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    // 音频大小
    private int minBufSize;
    private String recordPath = "";
    private IRecordListener mIRecordListener;
    private volatile boolean isRecording = false;
    private static RecorderOperator instance;
    private byte[] audioData;

    public static RecorderOperator getInstance() {
        if (null == instance) {
            synchronized (RecorderOperator.class) {
                if (null == instance) {
                    instance = new RecorderOperator();
                }

            }
        }
        return instance;
    }

    private RecorderOperator() {
    }

    private synchronized void initRecorder() {

        deInitRecorder();

        minBufSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig,
                audioFormat);
        mRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig,
                audioFormat, minBufSize);

        DebugLog.e("sampleRateInHz = " + sampleRateInHz + ", channelConfig = " + channelConfig
                + ", audioFormat = " + audioFormat + ", minBufSize = " + minBufSize);
    }

    private synchronized void deInitRecorder() {
        if (mRecord == null) {
            return;
        }

        mRecord.stop();
        mRecord.release();
        mRecord = null;

        isRecording = false;

    }

    public void setRecordPath(String path) {
        if (path != null && path.length() > 0) {
            recordPath = path;
        }
    }

    public void setRecordingListener(IRecordListener listener) {
        mIRecordListener = listener;
    }

    public void startRecord() {

        initRecorder();

        isRecording = true;
        //开启一个线程录音
        audioData = new byte[minBufSize];
        mRecord.startRecording();
        DebugLog.e("startRecording");
        AppExecutors.runOnIoThread(saveAudioDataRunnable);

        if (mIRecordListener != null) {
            mIRecordListener.onRecordingStart();
        }
        int readSize = 0;
        while (isRecording) {
            /*readSize = mRecord.read(audioData, 0, minBufSize);
            if (mIRecordListener != null) {
                mIRecordListener.onRecordingData(audioData, readSize);
            }

            if (keepSaveAudioData && AudioRecord.ERROR_INVALID_OPERATION != readSize) {
                try {
                    audioDataQueue.add(ByteBuffer.wrap(audioData, 0, readSize));
                } catch (Exception e) {
                    DebugLog.e("audioDataQueue exception, e.msg = " + e.getMessage());
                    audioDataQueue.clear();
                }
            }*/
        }

        keepSaveAudioData = false;
//        byte[] buffer = new byte[1];
//        audioDataQueue.add(ByteBuffer.wrap(buffer, 0, buffer.length));

        if (mIRecordListener != null) {
            mIRecordListener.onRecordingStop();
        }

        deInitRecorder();
    }

    public void stopRecord() {
        isRecording = false;

    }

    public int getAudioFormat() {
        return audioFormat;
    }

    public void setAudioFormat(int audioFormat) {
        this.audioFormat = audioFormat;
    }

    public int getSampleRateInHz() {
        return sampleRateInHz;
    }

    public void setSampleRateInHz(int sampleRateInHz) {
        this.sampleRateInHz = sampleRateInHz;
    }

    public int getChannelConfig() {
        return channelConfig;
    }

    public void setChannelConfig(int channelConfig) {
        this.channelConfig = channelConfig;
    }

    ///////////
    private volatile boolean keepSaveAudioData = true;
//    private BlockingQueue<ByteBuffer> audioDataQueue = new LinkedBlockingQueue<>(128);

    private Runnable saveAudioDataRunnable = new Runnable() {
        @Override
        public void run() {

            if (TextUtils.isEmpty(recordPath)) {
                keepSaveAudioData = false;
                return;
            }
//            BufferedOutputStream bos = null;
            FileOutputStream bos = null;

            try {

                File file = new File(recordPath);
                if (file.exists()) {
                    file.delete();
                }
//                bos = new BufferedOutputStream(new FileOutputStream(file));
                bos = new FileOutputStream(file);

                keepSaveAudioData = true;
                while (keepSaveAudioData) {

                    /*ByteBuffer byteBuffer = audioDataQueue.take();
                    if (byteBuffer != null && byteBuffer.array().length != 1) {
                        bos.write(byteBuffer.array(), 0, byteBuffer.array().length);
                        bos.flush();
                        byteBuffer = null;
                    }*/
                    int read = mRecord.read(audioData, 0, minBufSize);
                    if (mIRecordListener != null) {
                        mIRecordListener.onRecordingData(audioData, read);
                    }
                    if (AudioRecord.ERROR_INVALID_OPERATION != read) {
                        try {
                            bos.write(audioData);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {

//                audioDataQueue.clear();

                DebugLog.e("write file finish..........................");

                if (bos != null) {
                    try {
                        bos.flush();
                        bos.close();

                        PcmToWav pcmToWav = new PcmToWav();
                        pcmToWav.pcm2Wav(recordPath, recordPath + ".wav");

                    } catch (IOException ignored) {
                    }
                }
            }
        }
    };
}

